import os
import cv2
import numpy as np
from datetime import datetime
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QImage, QPixmap, QIcon
from PyQt5.QtWidgets import QWidget, QApplication, QDialog, QVBoxLayout, QHBoxLayout, QLabel, QSpinBox, QComboBox, \
    QPushButton, QSpacerItem, QSizePolicy, QGridLayout, QLineEdit, QCheckBox,QAbstractItemView
import sys
sys.path.append('.')
from ClientUi.controls.CustomList import CustomList, CustomListItemType
from ClientUi.controls.PathSelectWidget import PathSelectWidget
from get_config import config, config_save,global_camera_trigger_mode


class ImageCaptureDlg(QDialog):
    __cameraList = None
    __edtTrigger = None
    __img = None
    __path = None
    __autoSave = None
    __saveCurrentImage = None

    __annotationBtn = None # 标注按钮
    __saveCfgBtn = None # 保存配置按钮

    _rootPath = ''
    __topHeight = 30
    __bottomHeight = 90

    def __init__(self, coreProcess=None):
        super().__init__()
        currentPath = os.path.abspath(__file__)
        path = os.path.dirname(currentPath)
        clientUiPath = os.path.dirname(path)
        self.setWindowIcon(QIcon(f'{clientUiPath}\\images\\icon.ico'))  # 设置窗口图标
        self.setWindowTitle('图像调试')
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.resize(800, 600)
        self._rootPath = os.path.dirname(path)
        self.selectedcamid = -1
        self.btnCaptrue = None
        self.capturedimg = None
        self.CoreProcess = coreProcess
        self.__initUi()

    def __initUi(self):
        vl = QVBoxLayout()

        top = self.__createTopLayout()
        top.setContentsMargins(5,5,5,5)

        # 下区域 （保存按钮）
        bottomPanel = self.__createBottomWidget()

        vl.addLayout(top)
        vl.addWidget(bottomPanel)
        vl.setSpacing(0)
        vl.setContentsMargins(1,0,1,1)
        self.setLayout(vl)

    def __createTopLeftWidget(self):
        tlw = QWidget()
        tlw.setObjectName('ImgCap_left')
        vl = QVBoxLayout()
        lbTitle = QLabel('相机列表')
        lbTitle.setFixedHeight(self.__topHeight)
        subBottomWgt = QWidget()
        lbTrigger = QLabel('触发方式：')
        self.__edtTrigger = QLineEdit()  # 放在__cameraList创建的上面
        self.btnCaptrue = QPushButton('触发拍照') # 当前相机非软件触发时，该按钮不可见
        self.__edtTrigger.setReadOnly(True)
        grdlt = QGridLayout()
        grdlt.addWidget(lbTrigger, 0, 0)
        grdlt.addWidget(self.__edtTrigger, 0, 1)
        grdlt.addWidget(self.btnCaptrue, 1, 2, 1, 1, Qt.AlignRight)
        subBottomWgt.setLayout(grdlt)
        subBottomWgt.setFixedHeight(self.__bottomHeight)
        subBottomWgt.setContentsMargins(0,0,0,0)
        self.btnCaptrue.clicked.connect(self._onCapture)

        self.__cameraList = CustomList()       
        #self.__cameraList.horizontalHeader().setVisible(False)
        self.__cameraList.SetColumnTitleAndTypes((('名称', CustomListItemType.LABEL), ('IP', CustomListItemType.LABEL)))
        cameraNum = config['cameranum']
        self.__cameraList.setRowCount(cameraNum)
        self.__cameraList.itemClicked.connect(self._onItemSelected)
        for i in range(cameraNum):
            self.__cameraList.setRow(i, (config[f"camera{i+1}_name"], config[f"camera{i + 1}_devinfo"]))

        if cameraNum > 0:
            self.__cameraList.setSelectRow(0)
            self._onItemSelected(self.__cameraList.item(0,0))

        vl.addWidget(lbTitle)
        vl.addWidget(self.__cameraList)
        vl.addWidget(subBottomWgt)
        tlw.setLayout(vl)
        tlw.setFixedWidth(250)
        return tlw

    def __createTopRightWidget(self):
        trw = QWidget()
        trw.setObjectName('ImgCap_right')
        vl = QVBoxLayout()
        lbTitle = QLabel('')
        lbTitle.setFixedHeight(self.__topHeight)
        self.__img = QLabel()
        self.__img.setObjectName('ImgLabel')
        subBottomWgt = QWidget()
        self.__path = PathSelectWidget()
        if config['img_cap_save_path'] == '' or not os.path.exists(config['img_cap_save_path']):
            self.__path.setPlaceholderText('请先设置保存图像的路径')
            pass
        else:
            self.__path.setPath(config['img_cap_save_path'])
        self.__autoSave = QCheckBox('自动保存图像')
        self.__saveCurrentImage = QPushButton('保存当前图像')
        subVl = QVBoxLayout()
        subVl.addWidget(self.__path)
        subVl.addWidget(self.__autoSave)
        subVl.addWidget(self.__saveCurrentImage, 0, Qt.AlignRight)
        subBottomWgt.setLayout(subVl)
        subBottomWgt.setFixedHeight(self.__bottomHeight)
        subBottomWgt.setContentsMargins(0, 0, 0, 0)
        # Todo: 需要根据上次保存的配置，设置自动保存初始状态
        self.__autoSave.setChecked(config['img_cap_is_auto_saved'])
        self.__saveCurrentImage.clicked.connect(self._onSaveImage)
        vl.addWidget(lbTitle)
        vl.addWidget(self.__img)
        vl.addWidget(subBottomWgt)
        trw.setLayout(vl)
        trw.setMinimumWidth(300)
        return trw

    def __createTopLayout(self):
        hl = QHBoxLayout()
        tl = self.__createTopLeftWidget()
        tr = self.__createTopRightWidget()
        hl.addWidget(tl)
        hl.addWidget(tr)
        return hl

    def __createBottomWidget(self):
        bottomPanel = QWidget()
        bottomPanel.setObjectName('DevManager_bottomPanel')
        hl_bottom = QHBoxLayout()
        bottomPanel.setLayout(hl_bottom)
        hl_bottom.addSpacerItem(QSpacerItem(0, 50, QSizePolicy.Expanding, QSizePolicy.Fixed))
        self.__annotationBtn = QPushButton('标注')
        self.__annotationBtn.clicked.connect(self._onAnnotation)
        self.__saveCfgBtn = QPushButton('应用')
        self.__saveCfgBtn.clicked.connect(self._onApply)
        hl_bottom.addWidget(self.__annotationBtn, 0, Qt.AlignRight)
        hl_bottom.addWidget(self.__saveCfgBtn, 0, Qt.AlignRight)
        return bottomPanel

    def _onItemSelected(self, item):
        print(f'选择中了行{item.text()}')
        # 获取当前相机的触发方式，并显示
        self.selectedcamid = item.row()
        triggermode = config[f"camera{self.selectedcamid+1}_hardtrigger"]
        strtriggermode = global_camera_trigger_mode[triggermode]
        self.__edtTrigger.setText(strtriggermode)
        if self.btnCaptrue != None:
            if strtriggermode == '硬触发':
                self.btnCaptrue.setEnabled(False)
            else:
                self.btnCaptrue.setEnabled(True)

    def _onCapture(self):
        # 触发当前相机拍照（软触发）
        print('点击了【触发拍照】按钮')
        # # 模拟加载图像
        # self.capturedimg = cv2.imread(r'D:\Projects\yolo\yolov5_v70\runs\predict-seg\exp\Image_20240822171050103.jpg',1)
        if self.CoreProcess != None:
            self.showimg()
            if self.__autoSave.isChecked():
                self.save_jpg_img()

    def _onSaveImage(self):
        print('点击了【保存图像】按钮')
        # 保存文件路径、自动保存到文件
        self.save_jpg_img()

    def _onAnnotation(self):
        print('点击了【标注】按钮')
        # 切换到标注界面

    def _onApply(self):
        print('点击了【应用】按钮')
        # 保存文件路径、自动保存到文件
        if self.__path.getPath() == '设置保存图像路径':
            config['img_cap_save_path'] = ''
        else:
            config['img_cap_save_path'] = self.__path.getPath()

        config['img_cap_is_auto_saved'] = self.__autoSave.isChecked()
        config_save()
        # self.accept()

    def save_bmp_img(self):
        save_img_path = self.__path.getPath()
        if save_img_path != '' and save_img_path != '设置保存图像路径' and os.path.exists(save_img_path):
            filename = datetime.now().strftime("%Y%m%d-%H%M%S.%f")[:-3] 
            img_path = os.path.join(save_img_path, f'{filename}.bmp')            
            if self.check_is_image_data(self.capturedimg):
                cv2.imwrite(img_path, self.capturedimg)

    def save_jpg_img(self,quality=80):
        save_img_path = self.__path.getPath()
        if save_img_path != '' and save_img_path != '设置保存图像路径' and os.path.exists(save_img_path):
            filename = datetime.now().strftime("%Y%m%d-%H%M%S.%f")[:-3] 
            img_path = os.path.join(save_img_path, f'{filename}.jpg')       
            if self.check_is_image_data(self.capturedimg):
                cv2.imencode('.jpg', self.capturedimg, params=[cv2.IMWRITE_JPEG_QUALITY, quality])[1].tofile(img_path)

    def check_is_image_data(self,data):        
        # 检查是否为numpy数组
        if not isinstance(data, np.ndarray):
            return False
        
        # 检查维度，通常图像数据是3维或2维
        if data.ndim not in [2, 3]:
            return False
        
        # 检查数据类型，通常是uint8
        if data.dtype != np.uint8:
            return False
        
        # 如果是3维数据，检查通道数，通常是3(RGB)或4(RGBA)
        if data.ndim == 3 and data.shape[2] not in [3, 4]:
            return False
        
        return True 


    def imresize(self,img, k):
        sz = (int(img.shape[1]*k), int(img.shape[0]*k))
        img = cv2.resize(img, sz)
        return img  


    def showimg(self):
        if self.check_is_image_data(self.capturedimg):
            w1, h1 = self.__img .width(), self.__img .height()
            h, w  = self.capturedimg.shape[:2]
            s = min(w1/w, h1/h)
            img = self.imresize(self.capturedimg, s)
            h, w  = img.shape[:2]
            
            if len(img.shape)==3:
                img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # opencv读取的bgr格式图片转换成rgb格式
            else:
                img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)

            image = QImage(img.data, w, h, w*3, QImage.Format_RGB888)  # pyqt5转换成自己能放的图片格式
            jpg_out = QPixmap(image).scaled(w1, h1,aspectRatioMode=Qt.KeepAspectRatio)  # 转换成QPixmap
            # jpg_out = QPixmap(image).scaled(w1, h1)  # 转换成QPixmap
            self.__img.setScaledContents(False)

            self.__img.setPixmap(jpg_out)
            self.__img.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    try:
        current_path = os.path.abspath(__file__)
        path = os.path.dirname(current_path)
        path = os.path.dirname(path)
        app.setStyleSheet(open(f'{path}/styleSheet.qss', encoding='utf-8').read())
        window = ImageCaptureDlg()
        window.showNormal()
        sys.exit(app.exec_())

    except Exception as e:
        print(e)